/**
  ******************************************************************************
  * @file    main.c
  * @author  ashuai0110
  * @version V2.0
  * @date    2024-09-07
  * @brief   使用举例-ymodem
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "bsp.h"

#include "ymodem.h"

/* 私有宏定义-----------------------------------------------------------------*/
#define YMODEM_TX_RX_TEST               (1u) /* 0:测试发送 1:测试接收 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
static ymodem_t ymodem; /* ymodem实例 */
static uint8_t ymodemBuf[YMODEM_BUF_1K_MAX]; /* ymodem数据缓存区 */
static file_info_t fileInfo; /* 文件信息结构体 */

static uint8_t fileCnt = 0; /* 文件计数 */

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/


/**
  * @brief  This function handles SysTick Handler.
  *
  * @param  None
  *
  * @retval None
  */
void SysTick_Handler(void)
{
    /* 组件计时节拍接口 */
    mw_tick_inc(1);
}

/**
  * @brief  串口1中断
  */
void USART1_IRQHandler(void)
{
    /* 串口1空闲中断 */
    if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)
    {
        USART1->SR;
        USART1->DR;
        
        /* 这里写接收处理 */
        ymodem_write_rx_buf(&ymodem, usart1DmaRxBuf, sizeof(usart1DmaRxBuf) - DMA_GetCurrDataCounter(DMA1_Channel5));
        /* dma重配置 */
        bsp_usart1_dma_rx_reconfig(sizeof(usart1DmaRxBuf));
    }
}

/**
  * @brief  串口1接收的dma中断
  */
void DMA1_Channel5_IRQHandler(void)
{
    /* DMA传输完成中断 */
    if(DMA_GetITStatus(DMA1_IT_TC5) != RESET)
    {
        /* 这里写接收处理 */
        ymodem_write_rx_buf(&ymodem, usart1DmaRxBuf, sizeof(usart1DmaRxBuf));
        /* dma重配置 */
        bsp_usart1_dma_rx_reconfig(sizeof(usart1DmaRxBuf));
        
        DMA_ClearITPendingBit(DMA1_IT_TC5);
    }
}

/**
  * @brief  串口1发送的dma中断
  */
void DMA1_Channel4_IRQHandler(void)
{
    static uint16_t num;
    
    /* DMA传输完成中断 */
    if(DMA_GetITStatus(DMA1_IT_TC4) != RESET)
    {
        /* 这里写读取发送内容的处理 */
        num = ymodem_read_tx_buf(&ymodem, usart1DmaTxBuf, sizeof(usart1DmaTxBuf)); /* 读出数据 */
        /* dma重配置 */
        bsp_usart1_dma_tx_reconfig(num);
        
        DMA_ClearITPendingBit(DMA1_IT_TC4);
    }
}

/**
  * @brief  串口发送前准备函数
  * 
  * @param  enState : 0失能 1使能
  *
  * @retval None
  */
void usart1_tx_en(uint8_t enState)
{
    uint16_t num;
    
    if(enState)
    {
        num = ymodem_read_tx_buf(&ymodem, usart1DmaTxBuf, sizeof(usart1DmaTxBuf)); /* 读出数据 */
        bsp_usart1_dma_tx_reconfig(num); /* dma重配置 */
    }
    else
    {
        DMA_Cmd(DMA1_Channel4, DISABLE);
    }
}

/**
  * @brief  获取ymodem数据包回调函数
  * 
  * @param  packetNum : 数据包序号 首次从1开始 超出255回到0
  *
  * @param  data      : 有效数据缓冲区(需读出数据)
  *
  * @param  len       : 有效数据长度(包含填充内容0x1A)
  *
  * @retval None
  */
void ymodem_get_packet_callback(uint8_t packetNum, uint8_t *data, uint16_t *len)
{
    uint16_t lenTmp = *len;

    /* 文件信息 */
    if(ymodem_get_file_flag(&ymodem))
    {
        fileCnt++;
        ymodem_get_file_info(&ymodem, &fileInfo); /* 获取文件信息保存至fileInfo结构体 */
        MW_PRINT_FUNC("ymodem rec file:%d name:%s, size:%d Byte\r\n", fileCnt, fileInfo.fileName, fileInfo.fileSize);
    } /* 数据 */
    else
    {
        MW_PRINT_FUNC("ymodem packet num:%d, len:%d, data: ", packetNum, lenTmp);
        while(lenTmp--)
        {
            MW_PRINT_FUNC("%02X ", *data++);
        }
        MW_PRINT_FUNC("\r\n");
    }
}

/**
  * @brief  设置ymodem数据包回调函数
  * 
  * @param  packetNum : 数据包序号 首次从1开始 超出255回到0
  *
  * @param  data      : 有效数据存放区(需填充数据)
  *
  * @param  len       : 有效数据长度(不包含填充内容0x1A,组件自动填充)
  *
  * @retval None
  */
void ymodem_set_packet_callback(uint8_t packetNum, uint8_t *data, uint16_t *len)
{
    /* 文件信息 */
    if(ymodem_get_file_flag(&ymodem))
    {
        /* 只发送一个文件 */
        if(fileCnt < 1)
        {
            fileCnt++; /* 文件计数自增 */
            strcpy(fileInfo.fileName, "test_ymodem.txt\0"); /* 文件名 注意末尾加\0 */
            fileInfo.fileSize = 5000; /* 文件长度 */
        } /* 文件计数超出要发送的数量则设置文件长度为0 */
        else
        {
            fileInfo.fileSize = 0;
        }
        ymodem_set_file_info(&ymodem, &fileInfo); /* 设置文件信息从fileInfo结构体 */
    } /* 数据 */
    else
    {
        /* 用户自行计算数据量并在发送完全后给len赋值0 */
        *len = (fileInfo.fileSize >= YMODEM_DATA_1K_SIZE) ? YMODEM_DATA_1K_SIZE : fileInfo.fileSize;
        memset((void *)data, packetNum + 'A', *len);
        fileInfo.fileSize -= *len;
    }
}

/**
  * @brief  main
  */
int main(int argc, char *argv[])
{
    MW_VER_LOG("example-ymodem", 2, 0, 0);
    
    /* BSP初始化 */
    bsp_init();

    /* ymodem组件初始化 */
    ymodem_init(&ymodem, ymodemBuf, sizeof(ymodemBuf), usart1_tx_en, ymodem_get_packet_callback, ymodem_set_packet_callback, 3000, 2);
#if YMODEM_TX_RX_TEST
    /* 启动ymodem接收 */
    ymodem_rx_start(&ymodem, YMODEM_RX_FLAG_CRC);
#endif
    
    while(1)
    {
        static uint8_t ret;
#if YMODEM_TX_RX_TEST
        ret = ymodem_rx_poll(&ymodem); /* ymodem接收轮询处理 */
        if(MW_RET_OK == ret)
        {
            MW_DEBUG_LOG("ymodem rx success");
        }
        else if(MW_RET_ERR == ret)
        {
            MW_DEBUG_LOG("ymodem rx failed");
        }
        else if(MW_RET_TIMEOUT == ret)
        {
            MW_DEBUG_LOG("ymodem rx timeout");
        }
#else
        ret = ymodem_tx_poll(&ymodem); /* ymodem发送轮询处理 */
        if(MW_RET_OK == ret)
        {
            MW_DEBUG_LOG("ymodem tx success");
        }
        else if(MW_RET_ERR == ret)
        {
            MW_DEBUG_LOG("ymodem tx failed");
        }
        else if(MW_RET_TIMEOUT == ret)
        {
            MW_DEBUG_LOG("ymodem tx timeout");
        }
#endif
    }
}

